home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 24
/
Amiga Format AFCD24 (Feb 1998, Issue 108).iso
/
-in_the_mag-
/
emulation
/
amiga
/
uae-0.7.0b2
/
src
/
gengenblitter.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-20
|
20KB
|
1,039 lines
/*
* UAE - The Un*x Amiga Emulator
*
* Optimized blitter minterm function generator
*
* Copyright 1995,1996 Bernd Schmidt
* Copyright 1996 Alessandro Bissacco
*
* Overkill, n: cf. genblitter
*/
#include "sysconfig.h"
#include "sysdeps.h"
#include "config.h"
#include "options.h"
static void nop(int);
#if 0
typedef struct alloc_hdr
{
int size;
struct alloc_hdr *next, *prev;
void *from, *from2;
} *ahead;
static struct alloc_hdr ah_top = { 0, &ah_top, &ah_top, 0, 0 };
int nbytesmalloced = 0;
int malloc_cnt = 0;
static void *xmalloc(int sz)
{
ahead mem = (ahead)malloc(sz + sizeof(struct alloc_hdr));
mem->size = sz;
mem->next = &ah_top;
mem->prev = ah_top.prev;
ah_top.prev->next = mem;
ah_top.prev = mem;
mem->from = __builtin_return_address(0);
mem->from2 = __builtin_return_address(1);
malloc_cnt++;
nbytesmalloced += sz;
return mem + 1;
}
static void *xrealloc(void *mem, int sz)
{
if (mem == NULL)
return xmalloc(sz);
else {
ahead m = (ahead)mem;
m--;
nbytesmalloced += sz - m->size;
m->size = sz;
return ((ahead)realloc(m, sz + sizeof(struct alloc_hdr))) + 1;
}
}
static void xfree(void *mem)
{
ahead m = (ahead)mem;
m--;
m->next->prev = m->prev;
m->prev->next = m->next;
nbytesmalloced -= m->size;
malloc_cnt--;
free(m);
}
#else
#define xmalloc malloc
#define xfree free
#define xrealloc realloc
#endif
typedef struct tree_n {
enum tree_op { op_and, op_or, op_xor, op_not, op_a, op_b, op_c } op;
struct tree_n *left, *right;
} *tree;
static struct tree_n TRA = { op_a, NULL, NULL }, TRB = { op_b, NULL, NULL }, TRC = { op_c, NULL, NULL };
static tree tree_a = &TRA, tree_b = &TRB, tree_c = &TRC;
typedef struct {
tree *trees;
int space;
int ntrees;
} tree_vec;
static tree best_tree, main_tree;
static int best_cost = 65535;
static void kill_tree(tree *t)
{
if (*t != NULL && *t != tree_a && *t != tree_b && *t != tree_c) {
if ((*t)->left) kill_tree(&(*t)->left);
if ((*t)->right) kill_tree(&(*t)->right);
xfree(*t);
}
*t = NULL;
}
static tree dup_tree(tree t)
{
if (t == NULL || t == tree_a || t == tree_b || t == tree_c)
return t;
else {
tree nt = (tree)xmalloc(sizeof(struct tree_n));
nt->op = t->op;
nt->left = dup_tree(t->left);
nt->right = dup_tree(t->right);
return nt;
}
}
static tree new_op_tree(enum tree_op op, tree l, tree r)
{
tree t;
if (op == op_not && l->op == op_not) {
t = l->left;
xfree(l);
return t;
}
t = (tree)xmalloc(sizeof(struct tree_n));
t->left = l;
t->right = r;
t->op = op;
return t;
}
static int tree_cst(tree t, int *nota, int *notb, int *notc)
{
switch(t->op) {
case op_a:
case op_b:
case op_c:
return 0;
case op_not:
switch (t->left->op) {
case op_a:
if (*nota)
return 0;
*nota = 1;
return 4;
case op_b:
if (*notb)
return 0;
*notb = 1;
return 4;
case op_c:
if (*notc)
return 0;
*notc = 1;
return 4;
#if 0
case op_not:
return tree_cst(t->left->left, nota, notb, notc);
#endif
default:
break;
}
return 3 + tree_cst(t->left, nota, notb, notc);
case op_and:
case op_xor:
case op_or:
return 3 + tree_cst(t->left, nota, notb, notc) + tree_cst(t->right, nota, notb, notc);
}
return 0;
}
static int tree_cost(tree t)
{
int a = 0,b = 0,c = 0;
return tree_cst(t,&a,&b,&c);
}
static int eval(tree t)
{
int v = tree_cost(t);
if (v < best_cost) {
best_cost = v;
if (best_tree != NULL)
kill_tree(&best_tree);
best_tree = dup_tree(t);
}
return v;
}
static int tree_equal(tree a, tree b)
{
unsigned long mask = 0;
int i;
tree t2, t3;
if (a == b)
return 1;
if (a->op != b->op)
return 0;
if (a->op == op_not)
return tree_equal(a->left, b->left);
if (a->op != op_xor && a->op != op_or && a->op != op_and)
return 0;
if (tree_equal(a->left, b->left))
return tree_equal(a->right, b->right);
for (i = 0, t2 = a; t2->op == a->op; t2 = t2->right, i++)
;
for (t3 = b; t3->op == b->op; t3 = t3->right, i--)
;
if (i != 0)
return 0;
t2 = a;
for (;;) {
tree ttmp;
tree t3;
if (t2->op == a->op)
ttmp = t2->left;
else
ttmp = t2;
t3 = b;
for (i = 0;; i++) {
tree ttmp2;
if (t3->op == b->op)
ttmp2 = t3->left;
else
ttmp2 = t3;
if ((mask & (1 << i)) == 0 && tree_equal(ttmp, ttmp2)) {
mask |= 1 << i;
break;
}
if (t3->op != b->op)
return 0;
t3 = t3->right;
}
if (t2->op != a->op)
break;
t2 = t2->right;
}
return 1;
}
static int tree_isnormal(tree t)
{
if ((t->op == op_xor || t->op == op_and || t->op == op_or)
&& t->left->op == t->op)
return 0;
return 1;
}
static void normalize(tree *t)
{
if (*t == NULL)
return;
if ((*t)->op == op_not && (*t)->left->op == op_not) {
tree t2 = (*t)->left->left;
xfree((*t)->left);
xfree(*t);
*t = t2;
}
while (((*t)->op == op_xor || (*t)->op == op_and || (*t)->op == op_or)
&& (*t)->left->op == (*t)->op)
{
tree tmp = (*t)->left->left;
(*t)->left->left = (*t)->left->right;
(*t)->left->right = (*t)->right;
(*t)->right = (*t)->left;
(*t)->left = tmp;
}
normalize(&(*t)->left);
normalize(&(*t)->right);
}
static void add_vec(tree_vec *tv, tree t)
{
if (!tree_isnormal(t))
nop(2);
if (tv == NULL) {
eval(t);
kill_tree(&t);
} else {
int i;
for (i = 0; i < tv->ntrees; i++)
if (tree_equal(tv->trees[i], t)) {
kill_tree(&t);
return;
}
if (tv->ntrees == tv->space) {
tv->trees = (tree *)xrealloc(tv->trees, sizeof(tree)*(tv->space += 40));
}
tv->trees[tv->ntrees++] = t;
}
}
static void kill_vec(tree_vec *tv)
{
int i;
for (i = 0; i < tv->ntrees; i++)
kill_tree(tv->trees + i);
xfree(tv->trees);
}
static void init_vec(tree_vec *tv)
{
tv->ntrees = tv->space = 0;
tv->trees = NULL;
}
static void do_sprint_tree(char *s, tree *t)
{
switch ((*t)->op) {
case op_a:
strcat(s, "srca");
break;
case op_b:
strcat(s, "srcb");
break;
case op_c:
strcat(s, "srcc");
break;
case op_and:
strcat(s, "(");
do_sprint_tree(s, &(*t)->left);
strcat(s, " & ");
while ((*t)->right->op == op_and) {
t = &(*t)->right;
do_sprint_tree(s, &(*t)->left);
strcat(s, " & ");
}
do_sprint_tree(s, &(*t)->right);
strcat(s, ")");
break;
case op_or:
strcat(s, "(");
do_sprint_tree(s, &(*t)->left);
strcat(s, " | ");
while ((*t)->right->op == op_or) {
t = &(*t)->right;
do_sprint_tree(s, &(*t)->left);
strcat(s, " | ");
}
do_sprint_tree(s, &(*t)->right);
strcat(s, ")");
break;
case op_xor:
strcat(s, "(");
do_sprint_tree(s, &(*t)->left);
strcat(s, " ^ ");
while ((*t)->right->op == op_xor) {
t = &(*t)->right;
do_sprint_tree(s, &(*t)->left);
strcat(s, " ^ ");
}
do_sprint_tree(s, &(*t)->right);
strcat(s, ")");
break;
case op_not:
strcat(s, "~");
do_sprint_tree(s,&(*t)->left);
break;
}
}
static void sprint_tree(char *s, tree t)
{
tree tt = dup_tree(t);
*s = 0;
do_sprint_tree(s, &tt);
kill_tree(&tt);
}
static int treecmp(tree a, tree b)
{
if (b->op != a->op)
return 1;
if (a == b)
return 0;
if (a->op == op_not)
return treecmp(a->left, b->left);
return 1;
}
static int issrc(tree t)
{
return t->op == op_a || t->op == op_b || t->op == op_c;
}
static void do_opt(tree, tree_vec *, int);
static void opt_xor(tree t, tree_vec *tv);
static void opt_distrib(tree t, tree_vec *tv);
static void opt_demorgan(tree t, tree_vec *tv);
static void opt_not(tree_vec *tv_dst, tree_vec *tv_src)
{
int i;
for (i = 0; i < tv_src->ntrees; i++) {
tree t = tv_src->trees[i];
add_vec(tv_dst, new_op_tree(op_not, dup_tree(t), NULL));
}
}
static void demorgan(tree t, tree_vec *tv)
{
tree newt = NULL, t_l = NULL;
int neednot = 0;
if (t->op == op_not && (t->left->op == op_and || t->left->op == op_or))
t_l = dup_tree(t->left);
else if (t->op == op_and || t->op == op_or)
t_l = dup_tree(t), neednot = 1;
else
return;
if (t_l->op == op_and)
t_l->op = op_or;
else
t_l->op = op_and;
t_l->left = new_op_tree(op_not, t_l->left, NULL);
t_l->right = new_op_tree(op_not, t_l->right, NULL);
normalize(&t_l);
if (neednot) {
tree_vec tv2;
int i;
init_vec(&tv2);
opt_xor(t_l, &tv2);
opt_distrib(t_l, &tv2);
add_vec(&tv2, t_l);
#if 0
for (i = 0; i < tv2.ntrees; i++) {
add_vec(tv, new_op_tree(op_not, dup_tree(tv2.trees[i]), NULL));
}
#endif
opt_not(tv, &tv2);
kill_vec(&tv2);
} else {
opt_xor(t_l, tv);
opt_distrib(t_l, tv);
add_vec(tv, t_l);
}
}
static void opt_xor(tree t, tree_vec *tv)
{
tree_vec tv1, tv2;
tree tt1, tt2;
int i;
enum tree_op top, sop;
tree t1, t2, t3;
int n1 = 0, n2 = 0, ok1 = 0, ok2 = 0;
top = t->op;
if (top != op_or)
return;
sop = t->left->op;
if (sop != op_and || t->right->op != sop)
return;
if (t->left->left->op == op_not) {
n1 = 1;
t1 = t->left->left->left;
} else {
t1 = t->left->left;
}
if (t->left->right->op == op_not) {
n2 = 1;
t2 = t->left->right->left;
} else {
t2 = t->left->right;
}
if (t->right->left->op == op_not) {
if (n1 == 0 && tree_equal(t->right->left->left, t1))
ok1++;
if (n2 == 0 && tree_equal(t->right->left->left, t2))
ok2++;
} else {
if (n1 == 1 && tree_equal(t->right->left, t1))
ok1++;
if (n2 == 1 && tree_equal(t->right->left, t2))
ok2++;
}
if (t->right->right->op == op_not) {
if (n1 == 0 && tree_equal(t->right->right->left, t1))
ok1++;
if (n2 == 0 && tree_equal(t->right->right->left, t2))
ok2++;
} else {
if (n1 == 1 && tree_equal(t->right->right, t1))
ok1++;
if (n2 == 1 && tree_equal(t->right->right, t2))
ok2++;
}
if (ok1 != 1 || ok2 != 1)
return;
t3 = new_op_tree(op_xor, dup_tree(t1), dup_tree(t2));
if (n1 == n2)
t3 = new_op_tree(op_not, t3, NULL);
normalize(&t3);
add_vec(tv, t3);
init_vec(&tv1); init_vec(&tv2);
tt1 = new_op_tree(op_not, dup_tree(t1), NULL);
tt2 = new_op_tree(op_not, dup_tree(t2), NULL);
do_opt(tt1, &tv1, 0); do_opt(tt2, &tv2, 0);
kill_tree(&tt1); kill_tree(&tt2);
for (i = 0; i < tv1.ntrees; i++) {
t3 = new_op_tree(op_xor, dup_tree(tv1.trees[i]), dup_tree(t2));
if (n1 != n2)
t3 = new_op_tree(op_not, t3, NULL);
normalize(&t3);
add_vec(tv, t3);
}
for (i = 0; i < tv2.ntrees; i++) {
t3 = new_op_tree(op_xor, dup_tree(t1), dup_tree(tv2.trees[i]));
if (n1 != n2)
t3 = new_op_tree(op_not, t3, NULL);
normalize(&t3);
add_vec(tv, t3);
}
for (i = 0; i < tv1.ntrees; i++) {
int j;
for (j = 0; j < tv2.ntrees; j++) {
t3 = new_op_tree(op_xor, dup_tree(tv1.trees[i]), dup_tree(tv2.trees[j]));
if (n1 == n2)
t3 = new_op_tree(op_not, t3, NULL);
normalize(&t3);
add_vec(tv, t3);
}
}
kill_vec(&tv1); kill_vec(&tv2);
}
static tree opt_factor_tree(tree old, tree f, enum tree_op top, enum tree_op sop,
tree *remainder)
{
tree t1 = old;
tree t2 = NULL;
*remainder = NULL;
for (;;) {
int found_factor = 0;
tree t3 = NULL;
tree t4;
if (t1->op == top)
t4 = t1->left;
else
t4 = t1;
if (t4->op != sop) {
if (*remainder == NULL)
*remainder = dup_tree(t4);
else
*remainder = new_op_tree(top, *remainder, dup_tree(t4));
} else {
for (;;) {
tree t5;
if (t4->op == sop)
t5 = t4->left;
else
t5 = t4;
if (treecmp(t5, f) != 0) {
if (t3 == NULL)
t3 = dup_tree(t5);
else
t3 = new_op_tree(sop, t3, dup_tree(t5));
} else
found_factor = 1;
if (t4->op != sop)
break;
t4 = t4->right;
}
if (!found_factor) {
if (*remainder == NULL)
*remainder = t3;
else
*remainder = new_op_tree(top, *remainder, t3);
} else {
if (t2 == NULL)
t2 = t3;
else
t2 = new_op_tree(top, t2, t3);
}
}
if (t1->op != top)
break;
t1 = t1->right;
}
if (t2 == NULL || t2->op != top) {
if (*remainder != NULL)
kill_tree(remainder);
if (t2 != NULL)
kill_tree(&t2);
return NULL;
}
return t2;
}
static void opt_distrib(tree t, tree_vec *tv)
{
enum tree_op top, sop;
tree t1;
top = t->op;
if (top != op_and && top != op_or)
return;
sop = t->left->op;
if ((top == op_and && sop != op_or) || (top == op_or && sop != op_and))
return;
#if 0
t1 = t->right;
for (;;) {
if (t1->op == sop)
break;
if (t1->op != top)
return;
if (t1->left->op != sop)
return;
t1 = t1->right;
}
#endif
t1 = t->left;
for (;;) {
tree t3, t4, t5;
if (t1->op == sop)
t3 = t1->left;
else
t3 = t1;
t4 = opt_factor_tree(t, t3, top, sop, &t5);
if (t4 != NULL) {
tree_vec tv2;
int i;
init_vec(&tv2);
normalize(&t4);
do_opt(t4, &tv2, 0);
kill_tree(&t4);
for (i = 0; i < tv2.ntrees; i++) {
t4 = new_op_tree(sop, dup_tree(t3), dup_tree(tv2.trees[i]));
if (t5 != NULL)
t4 = new_op_tree(top, t4, dup_tree(t5));
normalize(&t4);
if (t5 != NULL) {
demorgan(t4, tv);
opt_xor(t4, tv);
}
add_vec(tv, t4);
}
kill_vec(&tv2);
if (t5 != NULL)
kill_tree(&t5);
}
if (t1->op != sop)
break;
t1 = t1->right;
}
}
struct perm_data {
int n;
int *a;
tree_vec *tvar;
tree_vec *tvparent;
enum tree_op op;
int neednot;
int didmorgan;
};
static void allperms(struct perm_data *pd, int p,
void (*f)(struct perm_data *))
{
if (p == pd->n)
f(pd);
else {
int i;
for (i = p; i < pd->n; i++) {
int tmp = pd->a[i];
pd->a[i] = pd->a[p];
pd->a[p] = tmp;
allperms(pd, p + 1, f);
tmp = pd->a[i];
pd->a[i] = pd->a[p];
pd->a[p] = tmp;
}
}
}
static void optimize(tree_vec *tv, tree subt, enum tree_op top)
{
tree_vec sub_tv;
int i;
if (subt->op != top) {
add_vec(tv, dup_tree(subt));
return;
}
init_vec(&sub_tv);
optimize(&sub_tv, subt->right, top);
for (i = 0; i < sub_tv.ntrees; i++) {
tree t1 = new_op_tree(top, dup_tree(subt->left), dup_tree(sub_tv.trees[i]));
demorgan(t1, tv);
opt_xor(t1, tv);
opt_distrib(t1, tv);
add_vec(tv, t1);
}
kill_vec(&sub_tv);
}
static void do_opt_perm_1(struct perm_data *pd, int i, tree rhs)
{
int j = pd->a[i];
int k;
i++;
for (k = 0; k < pd->tvar[j].ntrees; k++) {
tree lhs;
if (rhs == NULL)
lhs = dup_tree(pd->tvar[j].trees[k]);
else
lhs = new_op_tree(pd->op, dup_tree(pd->tvar[j].trees[k]), dup_tree(rhs));
if (i < pd->n) {
do_opt_perm_1(pd, i, lhs);
} else {
normalize(&lhs);
if (pd->neednot) {
int i;
tree_vec tvs;
init_vec(&tvs);
optimize(&tvs, lhs, lhs->op);
#if 0
for (i = 0; i < tvs.ntrees; i++)
add_vec(pd->tvparent, new_op_tree(op_not, dup_tree(tvs.trees[i]), NULL));
#endif
opt_not(pd->tvparent, &tvs);
kill_vec(&tvs);
} else
optimize(pd->tvparent, lhs, lhs->op);
}
kill_tree(&lhs);
}
nop(j);
}
void nop(int a)
{
}
static void do_opt_perm(struct perm_data *pd)
{
do_opt_perm_1(pd, 0, NULL);
}
static void do_opt(tree t, tree_vec *tv, int did_morgan)
{
/* if (!did_morgan)
demorgan(t, tv);
opt_distrib(t, tv);
opt_xor(t, tv);*/
if ((t->op == op_and || t->op == op_or)
|| (t->op == op_not
&& (t->left->op == op_and || t->left->op == op_or)))
{
int i, j;
struct perm_data pd;
tree t2, t3;
int neednot = t->op == op_not;
if (neednot)
t3 = t->left;
else
t3 = t;
pd.didmorgan = did_morgan;
pd.op = t3->op;
pd.neednot = neednot;
pd.tvparent = tv;
pd.n = 2;
t2 = t3->right;
while (t2->op == t3->op) {
pd.n++;
t2 = t2->right;
}
pd.a = (int *)xmalloc(sizeof(int)*pd.n);
pd.tvar = (tree_vec *)xmalloc(sizeof(tree_vec)*pd.n);
for (i = 0; i < pd.n; i++)
pd.a[i] = i;
t2 = t3; i = 0;
while (t2->op == t3->op) {
init_vec(pd.tvar + i);
do_opt(t2->left, pd.tvar + i, neednot && did_morgan);
t2 = t2->right;
i++;
}
init_vec(pd.tvar + i);
do_opt(t2, pd.tvar + i, 0);
allperms(&pd, 0, do_opt_perm);
for (i = 0; i < pd.n; i++) {
kill_vec(pd.tvar + i);
}
xfree(pd.tvar);
xfree(pd.a);
} else {
demorgan(t, tv);
opt_xor(t, tv);
opt_distrib(t, tv);
add_vec(tv, dup_tree(t));
}
}
static int bitset(int mt, int bit)
{
return mt & (1 << bit);
}
static char buffer[4096];
static int generate_expr(int minterm, int print)
{
int result = 0;
int firstor = 1;
int bits = 0;
int i;
int expr_bit[8], expr_dc[8], nexp = 0;
int expr_used[8];
tree t, t1 = NULL;
if (minterm == 0) {
if (print)
printf("0");
return 0;
}
if (minterm == 0xFF) {
if (print)
printf("0xFFFFFFFF");
return 0;
}
for(i=0; i<8; i++) {
if (bitset(minterm, i) && !bitset(bits,i)) {
int j;
int dontcare = 0;
int firstand = 1;
int bitbucket[8], bitcount;
bits |= 1<<i;
bitcount = 1; bitbucket[0] = i;
for(j=1; j<8; j *= 2) {
int success = 1;
int k;
for(k=0; k < bitcount; k++) {
if (!bitset(minterm, bitbucket[k] ^ j)) {
success = 0;
}
}
if (success) {
int l;
dontcare |= j;
for(l=bitcount; l < bitcount*2; l++) {
bitbucket[l] = bitbucket[l-bitcount] ^ j;
bits |= 1 << bitbucket[l];
}
bitcount *= 2;
}
}
expr_used[nexp] = 1;
expr_dc[nexp] = dontcare;
expr_bit[nexp++] = i;
}
}
t1 = NULL;
for (i = 0; i < nexp; i++) {
int j, firstand = 1;
tree t2 = NULL;
for (j = 1; j < 8; j *= 2) {
if (!(expr_dc[i] & j)) {
tree t3 = j == 1 ? tree_c : j == 2 ? tree_b : tree_a;
if ((expr_bit[i] & j) == 0)
t3 = new_op_tree(op_not, t3, NULL);
if (t2 != NULL)
t2 = new_op_tree(op_and, t3, t2);
else
t2 = t3;
result |= (j == 1 ? 4 : j == 2 ? 2 : 1);
}
}
if (t1 != NULL)
t1 = new_op_tree(op_or, t2, t1);
else
t1 = t2;
}
if (t1 != NULL) {
best_tree = NULL;
best_cost = 65535;
normalize(&t1);
main_tree = t1;
do_opt(main_tree, NULL, 0);
sprint_tree(buffer, best_tree);
printf("%s", buffer);
kill_tree(&main_tree);
kill_tree(&best_tree);
}
return result;
}
static void print_expr(int minterm)
{
generate_expr(minterm, 1);
printf("\n");
}
static void print_tree(tree t)
{
char buf[32768];
sprint_tree(buf, t);
printf("%s\n", buf);
}
static void generate_optable(void)
{
int minterm;
printf(" /* This file generated automatically - do not edit */\n\n");
printf("#include \"genblitter.h\"\n\n");
printf("struct blitop blitops[256] = {\n");
for (minterm = 0; minterm < 256; minterm++) {
int r;
printf(" /* %02x */ { \"", minterm);
r = generate_expr(minterm, 1);
printf("\", %d }%s\n", r, minterm == 255 ? "" : ",");
fflush(stdout);
}
printf("};\n");
}
int main(int argc, char **argv)
{
#if 0
tree t, t1, t2, t3;
tree_vec tv1;
int i;
t1 = new_op_tree(op_or, tree_b, tree_a);
t2 = new_op_tree(op_or, tree_c, tree_a);
t3 = new_op_tree(op_not, new_op_tree(op_xor, tree_c, tree_b), NULL);
t = new_op_tree(op_and, t1, new_op_tree(op_and, t2, t3));
init_vec(&tv1);
opt_distrib(t, &tv1);
for (i = 0; i < tv1.ntrees; i++)
print_tree(tv1.trees[i]);
kill_vec(&tv1);
#endif
generate_optable();
return 0;
}